///////////////////////////////////////////////////////////////////////////////
//
// This example demonstrates how to use FrameQueueSink to get the first X images even when 
// the notifyFrame callbacks takes too much time.
//

#define _WIN32_WINNT 0x0601

#include <iostream>

#include <tisudshl.h>

#include "CmdHelper.h"

using namespace DShowLib;

class overlay_paint_listener : public DShowLib::GrabberListener
{
public:
    //<<overlaycallback
    virtual void overlayCallback( DShowLib::Grabber& /*caller*/, smart_ptr<DShowLib::OverlayBitmap> pBitmap, const DShowLib::tsMediaSampleDesc& MediaSampleDesc )
    {
        if( pBitmap->getEnable() ) // Draw only, if the overlay bitmap is enabled.
        {
            char szText[25];
            sprintf_s( szText, "%04d ", MediaSampleDesc.FrameNumber );
			pBitmap->setFontTransparent( false );
            pBitmap->drawText( RGB( 255, 0, 0 ), 0, 0, szText );
        }
    }
    //>>
};

class sink_listener : public FrameQueueSinkListener
{
public:
	//<<sinkconnected
	virtual void    sinkConnected( FrameQueueSink& sink, const FrameTypeInfo& frameType )
	{
		UNREFERENCED_PARAMETER( frameType );
		
		sink.allocAndQueueBuffers( 10 );
	}
	//>>

    //<<frameready
    //////////////////////////////////////////////////////////////////////////
    /*! The framesQueued() method calls the saveImage method to save the image buffer to disk.
    */
	virtual void    framesQueued( FrameQueueSink& sink )
    {
		tFrameQueueBufferPtr buffer = sink.popOutputQueueBuffer();

		unsigned int frame_number = buffer->getFrameMetaData().mediaSampleDesc.FrameNumber;

        std::cout << "Buffer " << frame_number << " processed in sink_listener::framesQueued()." << std::endl;

        saveImage( buffer, frame_number );

        Sleep( 250 );       // induce a high latency penalty
    }
    //>>

    //<<saveimage
    //////////////////////////////////////////////////////////////////////////
    /*! Saves the passed in frame and increments the frame number
    */
    void	saveImage( const tFrameQueueBufferPtr& frame, unsigned int number )
    {
        char filename[MAX_PATH];
        sprintf_s( filename, "image%02i.bmp", number );

        saveToFileBMP( *frame, filename );
    }
    //>>
};


int main()
{
	InitLibrary();

	atexit( ExitLibrary );

	Grabber grabber;
											
	if( !setupDeviceFromFile( grabber ) )
	{
		return -1;
	}

    overlay_paint_listener  overlay_listener;

	
	// Enable the overlay bitmap to display the frame counter in the live video.
	grabber.setOverlayBitmapPathPosition( ePP_DEVICE );
	grabber.getOverlay( ePP_DEVICE )->setEnable( true );

//<<register
	// Register the pListener object for the overlay callback event.
	grabber.addListener( &overlay_listener, GrabberListener::eOVERLAYCALLBACK );

//>>

//<<sinktype
    sink_listener    listener_instance;

    // Create a FrameTypeInfoArray data structure describing the allowed color formats.
    FrameTypeInfoArray acceptedTypes = FrameTypeInfoArray::createRGBArray();

    // Create the frame sink
    tFrameQueueSinkPtr pSink = FrameQueueSink::create( listener_instance, acceptedTypes );

    // Apply the sink to the grabber.
	grabber.setSinkType( pSink );
//>>

//<<run
	grabber.startLive();				// Start the grabber.

    while( pSink->getInputQueueSize() != 0 ) // we have to wait until all 10 queued buffers have been drained
    {
        Sleep( 100 );
    }

    grabber.stopLive();					// Stop the grabber.
//>>
	
//<<saverest
	// Save the buffers for which CListener::frameReady() has not been called.
	// Since sink_listener::framesQueued() calls Sleep(100)
	
    tFrameQueueBufferList remaining_buffers = pSink->popAllOutputQueueBuffers();

	for( size_t i = 0; i < remaining_buffers.size(); i++ )
	{
		unsigned int frame_number = remaining_buffers[i]->getFrameMetaData().mediaSampleDesc.FrameNumber;

		std::cout << "Buffer " << frame_number << " processed in main()." << std::endl;

        listener_instance.saveImage( remaining_buffers[i], frame_number );
	}
//>>

    std::cout << "Press any key to continue!" << std::endl;
	std::cin.get();
	return 0;
}

